﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace ByteSite.Common
{
    public static class LambdaExtensions
    {
        public static Expression<Func<T, bool>> True<T>()
        {
            return f => true;
        }

        public static Expression<Func<T, bool>> False<T>()
        {
            return f => false;
        }

        public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expression1, Expression<Func<T, bool>> expression2)
        {
            ParameterExpression p = expression1.Parameters[0];
            SubstExpressionVisitor visitor = new SubstExpressionVisitor();
            visitor.subst[expression2.Parameters[0]] = p;
            Expression body = Expression.OrElse(expression1.Body, visitor.Visit(expression2.Body));
            return Expression.Lambda<Func<T, bool>>(body, p);
        }

        public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expression1, Expression<Func<T, bool>> expression2)
        {
            ParameterExpression p = expression1.Parameters[0];
            SubstExpressionVisitor visitor = new SubstExpressionVisitor();
            visitor.subst[expression2.Parameters[0]] = p;
            Expression body = Expression.AndAlso(expression1.Body, visitor.Visit(expression2.Body));
            return Expression.Lambda<Func<T, bool>>(body, p);
        }

        internal class SubstExpressionVisitor : System.Linq.Expressions.ExpressionVisitor
        {
            public Dictionary<Expression, Expression> subst = new Dictionary<Expression, Expression>();

            protected override Expression VisitParameter(ParameterExpression node)
            {
                Expression newValue;
                if (subst.TryGetValue(node, out newValue))
                {
                    return newValue;
                }
                return node;
            }
        }
    }
}